<?php

namespace App\Jobs;

use App\Models\Agent;
use App\Models\DailyReportStatistics;
use App\Models\Order;
use Carbon\Carbon;
use Illuminate\Support\Facades\Redis;

/**
 * Class DailyStatisticsJob
 * @package App\Jobs
 */
class DailyStatisticsJob extends Job
{
    /**
     * PS: 好像有点搞复杂了, 其实这里的统计光用 SQL 也行, 现在这样的话, 颗粒度比较细, 但是统计的东西比较粗
     */
    public function handle()
    {
        $yesterday = Carbon::yesterday(); // 第二天统计昨天的订单数据
        $today = Carbon::today()->startOfDay();
        $dateFormat = $yesterday->format('Y-m-d');
        $dateFormatForRedis = $yesterday->format('Ymd');

        /**
         * 初始化, 删除(脏)数据
         */
        ($numberOfLevelOrderKey = sprintf('index_daily_statistics:%s:number_of_level_order', $dateFormatForRedis)) && Redis::del($numberOfLevelOrderKey); // 删除 订单量 (大咖 精英 群主)
        foreach (Agent::LEVEL_MAP as $level => $levelItem) {
            Redis::del(sprintf('index_daily_statistics:%s:number_of_level_%s_agent_place_order', $dateFormatForRedis, $level)); // 删除 下单会员数 (大咖 精英 群主)
            Redis::del(sprintf('index_daily_statistics:%s:number_of_level_%s_performance_summary', $dateFormatForRedis, $level)); // 删除 销售额 (大咖 精英 群主)
        }

        /**
         * 当日订单统计
         */
        Order::query()
            ->with('agent:id,level')
            ->withoutGlobalScope('orderByIdDesc')
            ->where('order_date', $dateFormat) // 遍历昨天的订单
            ->whereIn('status', [Order::STATUS_NORMAL, Order::STATUS_SHIPPED])
            ->select([
                'id',
                'total_amount', // 业绩, 这里这个是会收到 售后影响的金额
                'agent_id',
            ])
            ->eachById(function (Order $order) use ($dateFormatForRedis, $numberOfLevelOrderKey) {
                if (empty($order['agent']) || empty($order['agent']['level'])) {
                    return;
                }

                Redis::hincrby($numberOfLevelOrderKey, $order['agent']['level'], 1); // 订单量 (大咖 精英 群主) ++
                Redis::hincrby(
                    sprintf('index_daily_statistics:%s:number_of_level_%s_agent_place_order', $dateFormatForRedis, $order['agent']['level']),
                    $order['agent']['id'],
                    1
                ); // 下单会员数 (大咖 精英 群主)_agent_id: ++
                Redis::hincrby(
                    sprintf('index_daily_statistics:%s:number_of_level_%s_performance_summary', $dateFormatForRedis, $order['agent']['level']),
                    $order['agent']['id'],
                    $order['total_amount']
                ); // 销售额 (大咖 精英 群主) ++
            });

        /**
         * 统计赋值
         */
        $updateData = [];
        // {level}订单数 赋值
        foreach ((array) Redis::hgetall($numberOfLevelOrderKey) as $level => $numberOfLevelOrder) {
            if (!isset(Agent::LEVEL_MAP[$level]['id'])) {
                continue;
            }
            $updateData['number_of_' . Agent::LEVEL_MAP[$level]['id'] . '_order'] = $numberOfLevelOrder;
        }
        foreach (Agent::LEVEL_MAP as $level => $levelItem) {
            // {level}下单会员数 赋值
            $updateData['number_of_' . $levelItem['id'] . '_place_order'] = Redis::hlen(sprintf('index_daily_statistics:%s:number_of_level_%s_agent_place_order', $dateFormatForRedis, $level)); // 下单会员数 (大咖 精英 群主)
            // {level}销售额 赋值
            $hscanCursor = 0;
            $updateData[$levelItem['id'] . '_performance_summary'] = 0;
            do {
                $hscanRes = Redis::hscan(sprintf('index_daily_statistics:%s:number_of_level_%s_performance_summary', $dateFormatForRedis, $level), $hscanCursor);
                $hscanCursor = (int) ($hscanRes[0] ?? 0);

                $updateData[$levelItem['id'] . '_performance_summary'] += array_sum($hscanRes[1]);
            } while ($hscanCursor != 0);
            // {level}活跃 赋值 (考虑到活跃会员数, 数据来源是当日计算的, 后面可能会没有, 这里如果没有在 redis 内找到, 就不做更新)
            if (($levelUv = (int) Redis::hlen(sprintf('index_daily_statistics:%s:number_of_level_%s_active_agent', $dateFormatForRedis, $level))) && $levelUv !== 0) {
                $updateData[$levelItem['id'] . '_uv'] = $levelUv;
            }
        }
        // 会员总数 (注册时间 <= 当天)
        $updateData['total_number_of_before_agents'] = Agent::query()->where('created_at', '<', $today)->count();
        // 'total_number_of_new_agents' 当日新增的会员数 (注册时间在 当天, 已有统计)

        /**
         * 设置 redis key 过期时间
         */
        Redis::expire($numberOfLevelOrderKey, 5 * 86400);
        foreach (Agent::LEVEL_MAP as $level => $levelItem) {
            Redis::expire(sprintf('index_daily_statistics:%s:number_of_level_%s_agent_place_order', $dateFormatForRedis, $level), 5 * 86400);
            Redis::expire(sprintf('index_daily_statistics:%s:number_of_level_%s_performance_summary', $dateFormatForRedis, $level), 5 * 86400);
        }

        // 最终 updateOrCreate T+1 统计数据
        DailyReportStatistics::query()->updateOrCreate(['date' => $dateFormat], $updateData);
    }
}
